﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Text;
using System.Windows.Forms;

using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;
using DoxygenBrowser.Common.Model;
using DoxygenBrowserAddin.Views;

using DoxygenBrowser.Common.InOut;
using System.Runtime.Serialization.Formatters.Binary;
using DoxygenBrowserAddin.Properties;
using DoxygenBrowserAddin.Data;

namespace DoxygenBrowserAddin.Controller
{
  public class DoxAddinController
  {
    public const string DOXDOC_EXTENSION = ".doxproj";
    private const string CMD_NAVIGATEFROMHERE = "NavigateFromHere";
    private const string CMD_DOXYGENWINDOW = "DoxygenWindow";
    private const string CMD_DOXYGENCONFIG = "DoxygenConfig";

    private DTE2 _applicationObject;
    private AddIn _addInInstance;

    private Window _toolWindow;
    private DoxygenBrowserAddin.Views.DoxygenBrowser _doxygenBrowserControl;
    private DoxygenBrowserAddin.Data.DoxygenConfig _doxConfig;
    private CmdShowDoxBrowser _cmdShowDoxBrowser;
    private CmdNavigateFromHere _cmdNavigateFromHere;
    private CmdDoxygenConfig _cmdDoxygenConfig;

    private List<AddInCommand> _lstCommands;

    public event EventHandler DoxygenConfigChanged;

    public DTE2 Application { get { return _applicationObject; } }
    public AddIn AddInInstance { get { return _addInInstance; } }

    private NotifyIcon _notifyIcon;

    private TokenDictionary _tokenDictionary;

    private SolutionEvents _solutionEvents;
    // Declare the variables at the class scope
    private Events2 _events;

    private void createHandlers()
    {
      // Use it somewhere in code
      _events = (Events2)_applicationObject.Events;

      _solutionEvents = _events.SolutionEvents;

      _solutionEvents.Opened += new _dispSolutionEvents_OpenedEventHandler(this.OnSolutionOpened);
      _solutionEvents.AfterClosing += new _dispSolutionEvents_AfterClosingEventHandler(this.OnAfterClosing);
    }

      

    public ReadOnlyCollection<AddInCommand> Commands
    {
      get { return new ReadOnlyCollection<AddInCommand>(_lstCommands); }
    }

    public TokenDictionary TokenDictionary
    {
      get { return _tokenDictionary; }
      set { _tokenDictionary = value; }
    }

    public bool IsDictionaryLoaded
    {
      get
      {
        return _tokenDictionary != null;
      }
    }

    public void Initialize(DTE2 applicationObject, AddIn addInInstance)
    {
      _applicationObject = applicationObject;
      _addInInstance = addInInstance;

      _lstCommands = new List<AddInCommand>();

      _cmdNavigateFromHere = new CmdNavigateFromHere(CMD_NAVIGATEFROMHERE, this);
      _lstCommands.Add(_cmdNavigateFromHere);

      _cmdShowDoxBrowser = new CmdShowDoxBrowser(CMD_DOXYGENWINDOW, this);
      _lstCommands.Add(_cmdShowDoxBrowser);

      _cmdDoxygenConfig = new CmdDoxygenConfig(CMD_DOXYGENCONFIG, this);
      _lstCommands.Add(_cmdDoxygenConfig);

      InitializeNotifyIcon();

      createMainView();
      createHandlers();
    }

    private void InitializeNotifyIcon()
    {
      _notifyIcon = new NotifyIcon();
      _notifyIcon.Visible = false;
      _notifyIcon.Icon = Resources.DoxygenIcon;
      _notifyIcon.MouseDoubleClick += new MouseEventHandler(_notifyIcon_MouseDoubleClick);
    }



    void _notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
    {
      Execute(_cmdShowDoxBrowser);
    }

    private void Execute(AddInCommand addinCommand)
    {
      vsCommandStatus status = vsCommandStatus.vsCommandStatusEnabled;
      object CommandText = null;
      _cmdShowDoxBrowser.QueryStatus(vsCommandStatusTextWanted.vsCommandStatusTextWantedNone, ref status, ref CommandText);
      if ((status & vsCommandStatus.vsCommandStatusEnabled) != 0)
      {
        object varIn = null;
        object varOut = null;
        _cmdShowDoxBrowser.Execute(vsCommandExecOption.vsCommandExecOptionDoDefault, ref varIn, ref varOut);
      }
    }

    public void ShowTip(string strTipText)
    {
      _notifyIcon.ShowBalloonTip(3000, "Doxygen Browser", strTipText, ToolTipIcon.Info);
    }

    private void createMainView()
    {
      try
      {
        object programmableObject = null;

        string guidString = "{9FFC9D9B-1F39-4763-A2AF-66AED06C799A}";
        Windows2 windows2 = (Windows2)_applicationObject.Windows;
        Assembly asm = Assembly.GetExecutingAssembly();
        _toolWindow = windows2.CreateToolWindow2(_addInInstance,
                                                 asm.Location,
                                                 typeof(DoxygenBrowserAddin.Views.DoxygenBrowser).FullName,
                                                 "Doxygen",
                                                 guidString,
                                                 ref programmableObject);
        _toolWindow.Visible = true;
        _doxygenBrowserControl = (Views.DoxygenBrowser)_toolWindow.Object;
        _doxygenBrowserControl.SetController(this);
        _doxygenBrowserControl.NavigateHome();
        _toolWindow.IsFloating = false;
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.Message + "\n" + ex.StackTrace.ToString());
      }
    }

    public AddInCommand GetCommand(string strCommandName)
    {
      foreach (AddInCommand command in _lstCommands)
      {
        if (command.CommandName == strCommandName)
        {
          return command;
        }
      }
      return null;
    }

    public void OnShowDoxBrowser()
    {
      _doxygenBrowserControl.NavigateHome();
      _toolWindow.Visible = true;
    }

    private string _doxygenConfigPath;
    public string DoxygenConfigPath
    {
      get { return _doxygenConfigPath; }
      set { _doxygenConfigPath = value; }
    }

    public DoxygenConfig DoxygenConfig
    {
      get { return _doxConfig; }
      set
      {
        bool bChanged = (_doxConfig != value);
        _doxConfig = value;
        OnDoxygenConfigChanged();

      }
    }


    public void OnSolutionOpened()
    {
      if (DoxygenConfig != null)
      {
        clearProject();
      }

      string strDoxConfigFile = getDoxConfigPathFromSolution(_applicationObject.Solution.FullName);
      FileInfo fileInfo = new FileInfo(strDoxConfigFile);
      if (fileInfo.Exists)
      {
        if (openDoxygenConfigFile(fileInfo.FullName))
        {
          CreateTokenDictionary();
          _doxygenBrowserControl.NavigateHome();

        }
      }

    }

    private bool openDoxygenConfigFile(string strDoxConfigPath)
    {
      DoxygenConfigPath = strDoxConfigPath;
      DoxygenConfig doxygenConfig= new DoxygenConfig();
      doxygenConfig.Load(strDoxConfigPath);
      this.DoxygenConfig = doxygenConfig;
      return true;
    }

    private void openTDictionary()
    {
      string strDocPath = GetDoxHtmlDirectory();
      strDocPath = Path.Combine(strDocPath, "tokens.tdic");

      TokenDictionary tokenDictionary = new TokenDictionary();

      FileInfo fileInfo = new FileInfo(strDocPath);

      if (fileInfo.Exists)
      {
        TDictionaryFileLoader tDictionaryFileLoader = new TDictionaryFileLoader(strDocPath);
        tDictionaryFileLoader.TokenDictionaryLoaded += new EventHandler(tDictionaryFileLoader_TokenDictionaryLoaded);
        tDictionaryFileLoader.Load();
      }
    }

    void tDictionaryFileLoader_TokenDictionaryLoaded(object sender, EventArgs e)
    {
      TDictionaryFileLoader tDictionaryFileLoader = sender as TDictionaryFileLoader;
      TokenDictionary = tDictionaryFileLoader.TokenDictionary;
    }


    private string getDoxConfigPathFromSolution(string strSolutionFullPath)
    {
      FileInfo solutionFileInfo = new FileInfo(strSolutionFullPath);
      string strDirectoryPath = solutionFileInfo.Directory.FullName;

      string strDoxProjFileName = Path.GetFileNameWithoutExtension(strSolutionFullPath) + DOXDOC_EXTENSION;

      string strResult = Path.Combine(strDirectoryPath, strDoxProjFileName);
      return strResult;
    }

    private void clearProject()
    {
      DoxygenConfig = null;
      TokenDictionary = null;
      DoxygenConfigPath = string.Empty;
    }


    public void OnAfterClosing()
    {
      clearProject();
    }

    public void NavigateTo(string strBasePath, FileLocation fileLocation)
    {
      string strPath = strBasePath;

      if (!string.IsNullOrEmpty(strBasePath))
      {
        strPath += "\\";
      }

      strPath += fileLocation.Path;
      if (fileLocation.HasAnchor)
      {
        strPath += "#";
        strPath += fileLocation.Anchor;
      }
      this._doxygenBrowserControl.Navigate(strPath);
      this._toolWindow.Activate();
    }

    public void CreateTokenDictionary()
    {
      string strDocFullPath = GetDoxHtmlDirectory();
      string strTokenFilePath = Path.Combine(strDocFullPath, "tokens.xml");

      TokenDictionaryLoader loader = new TokenDictionaryLoader(strTokenFilePath);
      loader.Process();
      TokenDictionary = loader.TokenDictionary;
    }

    public string GetDoxHtmlDirectory()
    {
      string strDirectoryName = Path.GetDirectoryName(DoxygenConfigPath);
      string strDoxHtmlPath = string.Empty;

      if (DoxygenConfig != null)
      {
        strDoxHtmlPath = DoxygenConfig.DoxHtmlPath;
      }
      return Path.Combine(strDirectoryName, strDoxHtmlPath);
    }



    public DoxygenConfig CreateDoxConfig(string strDoxConfigPath)
    {
      DoxygenConfigPath = strDoxConfigPath;
      DoxygenConfig doxygenConfig = new DoxygenConfig();
      doxygenConfig.Save(strDoxConfigPath);
      DoxygenConfig = doxygenConfig;

      return doxygenConfig;
    }

    public void CheckSolution()
    {
      if ((_applicationObject.Solution != null) &&
        _applicationObject.Solution.IsOpen)
      {
        OnSolutionOpened();
      }
    }

    public void Finalize()
    {
      this._notifyIcon.Visible = false;
    }

    internal void OnDoxygenConfigChanged()
    {
      if(DoxygenConfigChanged!=null)
      {
        DoxygenConfigChanged(this, EventArgs.Empty);
      }
    }
  }
}
